home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Mac OS USB DDK / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-10  |  11.7 KB  |  357 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <DriverServices.h>
  16. #include <USB.h>
  17. #include <LowMem.h>
  18.  
  19. #include "MouseModule.h"
  20.  
  21. usbMousePBStruct myMousePB;
  22.  
  23. void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock)
  24. {
  25.     paramblock->usbReference = theInterfaceRef;
  26.     paramblock->pbVersion = kUSBCurrentPBVersion;
  27.     
  28.     paramblock->usb.cntl.WIndex = 0;             
  29.     paramblock->usb.cntl.WValue = 0;
  30.     
  31.     paramblock->usbBuffer = nil;        
  32.     paramblock->usbActCount = 0;
  33.     paramblock->usbReqCount = 0;
  34.     paramblock->usbFlags = 0;
  35.     paramblock->usbOther = 0;
  36.     
  37.     paramblock->usbStatus = noErr;
  38. }
  39.  
  40.  
  41.  
  42. Boolean immediateError(OSStatus err)
  43. {
  44.     return((err != kUSBPending) && (err != noErr) );
  45. }
  46.  
  47. void MouseInitiateTransaction(USBPB *pb)
  48. {
  49. register usbMousePBStruct *pMousePB;
  50. OSStatus myErr;
  51.  
  52.     pMousePB = (usbMousePBStruct *)(pb);
  53.     pMousePB->transDepth++;
  54.     if (pMousePB->transDepth < 0)
  55.     {
  56.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (initiation)", pMousePB->pb.usbRefcon );
  57.     }
  58.     
  59.     if (pMousePB->transDepth > 1)
  60.     {
  61.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (initiation)", pMousePB->pb.usbRefcon );
  62.     }
  63.     
  64.     if (pMousePB->driverRemovalPending)
  65.     {
  66.         pMousePB->pb.usbRefcon = kReturnFromDriver;
  67.         return;
  68.     }
  69.  
  70.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  71.     {
  72.         case kConfigureInterface:
  73.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  74.             
  75.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  76.             pMousePB->pb.usbRefcon |= kCompletionPending;
  77.             
  78.             myErr = USBConfigureInterface( &pMousePB->pb );
  79.             if(immediateError(myErr))
  80.             {
  81.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kConfigureInterface - immediate error", myErr);
  82.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  83.             }
  84.             break;
  85.         
  86.         case kSetProtocol:
  87.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  88.             
  89.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  90.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  91.             pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  92.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  93.             
  94.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  95.             pMousePB->pb.usbRefcon |= kCompletionPending;
  96.         
  97.             myErr = USBDeviceRequest(&pMousePB->pb);
  98.             if (immediateError(myErr))
  99.             {
  100.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetProtocol - immediate error", myErr);
  101.             }
  102.             break;
  103.             
  104.         case kSetIdleRequest:
  105.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  106.             
  107.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  108.             
  109.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  110.             pMousePB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  111.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  112.             
  113.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  114.             pMousePB->pb.usbRefcon |= kCompletionPending;
  115.  
  116.             myErr = USBDeviceRequest(&pMousePB->pb);
  117.             if(immediateError(myErr))
  118.             {
  119.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetIdleRequest - immediate error", myErr);
  120.             }
  121.             break;
  122.  
  123.         case kFindPipe:
  124.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  125.             
  126.             pMousePB->pb.usbFlags = kUSBIn;
  127.             pMousePB->pb.usbClassType = kUSBInterrupt;
  128.             
  129.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  130.             pMousePB->pb.usbRefcon |= kCompletionPending;
  131.         
  132.             myErr = USBFindNextPipe( &pMousePB->pb );
  133.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  134.             {
  135.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kFindPipe - immediate error", myErr);
  136.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  137.             }
  138.             break;
  139.         
  140.         case kClearFeature:
  141.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a clear feature on the interrupt endpoint", pMousePB->pipeRef);
  142.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  143.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
  144.             
  145.             pMousePB->pb.usb.cntl.BRequest = kUSBRqClearFeature;
  146.             pMousePB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall;
  147.             
  148.             pMousePB->pb.usbFlags = kUSBAddressRequest;                /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */
  149.  
  150.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  151.             pMousePB->pb.usbRefcon |= kCompletionPending;
  152.  
  153.             myErr = USBDeviceRequest(pb);
  154.             if(immediateError(myErr))
  155.             {
  156.                 USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, kMouseModuleName": kClearFeature - immediate error", myErr);
  157.             }
  158.             break;
  159.                 
  160.         case kReadInterruptPipe:
  161.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  162.  
  163.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  164.             pMousePB->pb.usbReqCount = pMousePB->maxPacketSize;
  165.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  166.             
  167.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  168.             pMousePB->pb.usbRefcon |= kCompletionPending;
  169.         
  170.             myErr = USBIntRead(&pMousePB->pb);
  171.             if(immediateError(myErr))
  172.             {
  173.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Read Interrupt Pipe (ImmediateError)", myErr);
  174.             }
  175.             break;
  176.             
  177.         default:
  178.             USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  179.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  180.             break;
  181.     }
  182.     
  183. // At this point the control is returned to the system.  If a USB transaction
  184. // has been initiated, then it will call the Complete procs
  185. // (below) to handle the results of the transaction.
  186. }
  187.  
  188.  
  189. void MouseCompletionProc(USBPB *pb)
  190. {
  191. register usbMousePBStruct *pMousePB;
  192. unsigned char    * errstring;
  193. USBPipeState     pipeState;
  194.  
  195.     pMousePB = (usbMousePBStruct *)(pb);
  196.     pMousePB->transDepth--;
  197.     if (pMousePB->transDepth < 0)
  198.     {
  199.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (completion)", pMousePB->pb.usbRefcon );
  200.     }
  201.     
  202.     if (pMousePB->transDepth > 1)
  203.     {
  204.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (completion)", pMousePB->pb.usbRefcon );
  205.     }
  206.     
  207.     if(pMousePB->pb.usbStatus != noErr)                                                        // was there an error?
  208.     {
  209.         switch(pMousePB->pb.usbRefcon & 0x0fff)                                                // yes, so show where the error occurred
  210.         {
  211.             case kSetProtocol:                    errstring = kMouseModuleName": Error during kSetProtocol"; break;
  212.             case kSetIdleRequest:                  errstring = kMouseModuleName": Error during kSetIdleRequest"; break;
  213.             case kConfigureInterface:            errstring = kMouseModuleName": Error during kConfigureInterface"; break;
  214.             case kFindPipe:                      errstring = kMouseModuleName": Error during kFindPipe"; break;
  215.             case kClearFeature:                  errstring = kMouseModuleName": Error during kClearFeature"; break;
  216.             case kReadInterruptPipe:
  217.                 {
  218.                 errstring = kMouseModuleName": Error during ReadInterruptPipe";
  219.                 LMSetMouseButtonState(0x80);    // release any possibly held-down mouse button
  220.                 break;
  221.                 }
  222.             default:                              errstring = kMouseModuleName": Error occurred, but state is unknown"; break;
  223.         };
  224.         USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & 0x0fff));
  225.         
  226.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  227.         pMousePB->pb.usbRefcon |= kRetryTransaction;
  228.         pMousePB->retryCount--;
  229.         
  230.         if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon&pMousePB->pb.usbRefcon & 0x0fff) == kSetIdleRequest))
  231.         {
  232.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Device doesn't accept SetIdle", pMousePB->interfaceRef);
  233.             pMousePB->pb.usbRefcon = kFindPipe;
  234.             pMousePB->pb.usbStatus = noErr;
  235.         }
  236.         else
  237.         {
  238.             if ((!pMousePB->retryCount)    || (pMousePB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  239.             {                                                                                // or received an abort?
  240.                 USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe abort or unable to recover from error", pMousePB->interfaceRef);
  241.                 pMousePB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  242.                 pMousePB->intPipeAborted = true;    
  243.             }
  244.             else                                                                            // if it didn't abort and there's retries left, then...
  245.             {
  246.                 if (pMousePB->pipeRef)                                                        // check if the pipe is open.
  247.                 {
  248.                     USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                // yes, so what it's state?
  249.                     if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  250.                     {
  251.                         USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  252.                         USBClearPipeStallByReference(pMousePB->pipeRef);
  253.                     }
  254.                 }
  255.             }
  256.         }
  257.     }
  258.     else
  259.     {
  260.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  261.         pMousePB->retryCount = kMouseRetryCount;
  262.     }
  263.  
  264.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  265.     {                                                
  266.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  267.         switch(pMousePB->pb.usbRefcon)
  268.         {
  269.             case kConfigureInterface:
  270.                 pMousePB->pb.usbRefcon = kSetProtocol;
  271.                 break;
  272.                 
  273.             case kSetProtocol:
  274.                 pMousePB->pb.usbRefcon = kFindPipe;
  275.                 break;
  276.                 
  277.             case kSetIdleRequest:
  278.                 pMousePB->pb.usbRefcon = kFindPipe;
  279.                 break;
  280.                 
  281.             case kFindPipe:
  282.                 pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue;
  283.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  284.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  285.                 break;
  286.                 
  287.             case kReadInterruptPipe:
  288.                 NotifyRegisteredHIDUser(pMousePB->hidDeviceType, pMousePB->hidReport);
  289.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  290.                 break;
  291.  
  292.             default:
  293.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction completed with bad refcon value", pMousePB->pb.usbRefcon );
  294.                 pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  295.                 break;
  296.         }
  297.     }
  298.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver) && (!pMousePB->driverRemovalPending))
  299.         MouseInitiateTransaction(pb);
  300. }
  301.  
  302.  
  303. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef)
  304. {
  305. #pragma unused (interfacenum)
  306.  
  307. static Boolean beenThereDoneThat = false;
  308.  
  309.     if(beenThereDoneThat)
  310.     {
  311.         USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kMouseModuleName" is not reentrant", 0);
  312.         return;
  313.     }
  314.     beenThereDoneThat = true;
  315.     
  316.     // DebugStr("\pIn Mouse Interface Entry routine");
  317.  
  318.     myMousePB.driverRemovalPending = false;
  319.     myMousePB.intPipeAborted = false;    
  320.  
  321.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  322.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;            
  323.     
  324.     myMousePB.transDepth = 0;                            
  325.     myMousePB.retryCount = kMouseRetryCount;
  326.       
  327.     myMousePB.pSHIMInterruptRoutine = nil;
  328.     myMousePB.pSavedInterruptRoutine = nil;
  329.  
  330.     myMousePB.interfaceRef = theInterfaceRef;        
  331.     myMousePB.pipeRef = nil;        
  332.     
  333.     InitParamBlock(theInterfaceRef, &myMousePB.pb);
  334.     
  335.     myMousePB.pb.usbReference = theInterfaceRef;
  336.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  337.     myMousePB.pb.usbRefcon = kConfigureInterface;        
  338.     
  339.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  340.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  341.     {
  342.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  343.     }
  344.     else
  345.     {
  346.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  347.     }
  348.     
  349.     myMousePB.pCursorDeviceInfo = 0;                
  350.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  351.  
  352.     MouseInitiateTransaction(&myMousePB.pb);
  353. }
  354.  
  355.  
  356.  
  357.